package com.maniu.h264maniu;

import android.content.res.AssetManager;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.util.Log;
import android.view.Surface;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

public class H264Player implements Runnable {
    //    数据源
    //    解码器
    private MediaCodec mediaCodec;
    private AssetManager assetManager;

    public H264Player(AssetManager assetManager, Surface surface) {
        this.assetManager = assetManager;
        //surface    ffmpeg
        //    显示   目的   surface
        //具体编码名称  h264  h265  vp8 vp9      编码的历史  编码   ITU-T  ISO  名字
        //ISO  的   正规的  mpeg4-avc    h264 编码格式 是有限的
        //初始化
        try {
            mediaCodec = MediaCodec.createDecoderByType("video/avc");
            MediaFormat mediaformat = MediaFormat.createVideoFormat("video/avc",
                    368, 384);
            mediaformat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
            // 自己的参数  才是 交给dsp
            mediaCodec.configure(mediaformat, surface, null, 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //当前支持  硬解H264
        Log.i("david", "支持: ");
    }

    public void play() {
        mediaCodec.start();
        new Thread(this).start();
    }

    @Override
    public void run() {
        //  解码   休息10min
        // 这个宽高设置小了会不会有问题，如果解析sps真实数据宽高远远大于设置的宽高

        try {
            decodeH264();
        } catch (Exception e) {
            Log.i("david", "run: " + e.toString());
        }
    }

    private void decodeH264() {
        byte[] bytes = null;
        try {
            // bytes 数组里面
            bytes = getBytes(assetManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int startIndex = 0;
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        while (true) {
            int nextFrameStart = findByFrame(bytes, startIndex + 2, bytes.length);
            //        ByteBuffer[] byteBuffers= mediaCodec.getInputBuffers();
            int inIndex = mediaCodec.dequeueInputBuffer(10000);
            // 8K
            if (inIndex >= 0) {
                ByteBuffer byteBuffer = mediaCodec.getInputBuffer(inIndex);
                //  到底丢多少      文件大小 99M  3M崩了
                //            次数 帧来丢   一帧的内容
                //                byte
                int length = nextFrameStart - startIndex;
                Log.i("david", "decodeH264: 输入  " + length);
                //                丢一部分   数据 到容器 length
                byteBuffer.put(bytes, startIndex, length);
                //dsp   bytebuffer   dsp 1        dsp   索引   容器 2
                mediaCodec.queueInputBuffer(inIndex, 0, length, 0, 0);
                startIndex = nextFrameStart;
            }
            // 解码了  索引     索引 已经 3秒   dsp  数据
            //            8K 是1  不是
            // 大于1   等于 小于2
            int outIndex = mediaCodec.dequeueOutputBuffer(info, 10000);
            if (outIndex >= 0) {
                try {
                    Thread.sleep(33);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mediaCodec.releaseOutputBuffer(outIndex, true);
            }
        }

    }

    private int findByFrame(byte[] bytes, int start, int totalSize) {
        for (int i = start; i <= totalSize - 4; i++) {
            if (((bytes[i] == 0x00) && (bytes[i + 1] == 0x00) && (bytes[i + 2] == 0x00) && (bytes[i + 3] == 0x01))
                    || ((bytes[i] == 0x00) && (bytes[i + 1] == 0x00) && (bytes[i + 2] == 0x01))) {
                return i;
            }
        }
        return -1;
    }

    public byte[] getBytes(AssetManager assetManager) throws IOException {
        InputStream is = assetManager.open("out.h264");
        int len;
        int size = 1024;
        byte[] buf;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        buf = new byte[size];
        while ((len = is.read(buf, 0, size)) != -1)
            bos.write(buf, 0, len);
        buf = bos.toByteArray();
        return buf;
    }
}
